package com.pakazaka.player;

import com.pakazaka.enemies.BasicEnemy;
import com.pakazaka.enums.MoveDirectionType;
import com.pakazaka.layer.TiledLayer;
import com.pakazaka.layer.tiles.Tile;
import com.pakazaka.roguelike.body.BodyPart;
import static com.pakazaka.simplecrawler.ArrayListUtils.getEnemyAt;
import com.pakazaka.simplecrawler.Core;
import static com.pakazaka.simplecrawler.Core.getInstance;
import com.pakazaka.testItemsSystem.Item;
import java.awt.Graphics;
import java.awt.Image;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Random;
import static javax.imageio.ImageIO.read;

/**
 * Basic stranger class; superclass for Player and all enemies.
 *
 * @author Remi
 */
public abstract class BasicStranger {

    protected String nick;
    protected int stepsPassed;
    protected Image sprite;
    private int drawBlocksY, drawBlocksX;
    /**
     * Absolute stranger coordinates in tiles (stars from map 0:0).
     */
    private int absoluteBlocksY, absoluteBlocksX;
    private final ArrayList<Item> inventory = new ArrayList<>();

    public ArrayList<Item> getInventory() {
        return inventory;
    }
    private final Random rnd = new Random();
    protected int weight, maxCarryWeight = -1;
    protected int volume = 0, maxCarryVolume = 50000; //milliliters, that is 50 liters
    private Equip equip;
    private int speed;
    /**
     * Body part; has HP and Type.
     */
    protected BodyPart bodyHead = new BodyPart(100, BodyPart.BP_HEAD),
            bodyTorso = new BodyPart(100, BodyPart.BP_TORSO),
            bodyHands = new BodyPart(100, BodyPart.BP_HANDS),
            bodyLegs = new BodyPart(100, BodyPart.BP_LEGS);

    public void setAbsoluteBlocksY(int absoluteBlocksY) {
        this.absoluteBlocksY = absoluteBlocksY;
    }

    public void setAbsoluteBlocksX(int absoluteBlocksX) {
        this.absoluteBlocksX = absoluteBlocksX;
    }

    public BasicStranger(String pathToSprite) {
        try {
            sprite = read(getClass().getResourceAsStream(pathToSprite));
        } catch (IOException ex) {
            System.out.println("Cannot load player sprite.");
        }
    }

    public final void addItem(Item item) {
        if (volume < maxCarryVolume) {
            inventory.add(item);
            volume += item.getVolume();
        }
        item.generateBind(this);
    }

    public final void removeItem(Item item, BasicStranger player) {
        inventory.remove(item);
        volume -= item.getVolume();
    }

    public final void replaceItem(Item oldItem, Item newItem, boolean newItemExists) {
        inventory.remove(oldItem);
        volume -= oldItem.getVolume();
        if (newItemExists) {
            inventory.add(newItem);
            volume += newItem.getVolume();
        }
    }

    public Equip getEquip() {
        return equip;
    }

    public void setEquip(Equip equip) {
        this.equip = equip;
    }

    public final ArrayList<Item> getItems() {
        return inventory;
    }

    public int getSteps() {
        return stepsPassed;
    }

    public boolean canGetItem() {
        return volume < maxCarryVolume;
    }

    public int getMaxCarryVolume() {
        return maxCarryVolume;
    }

    public int getCarryVolume() {
        return volume;
    }

    public void setNick(String nick) {
        this.nick = nick;
    }

    public String getNick() {
        return nick;
    }

    public BodyPart getBodyPart(int id) {
        switch (id) {
            case BodyPart.BP_HEAD:
                return bodyHead;
            case BodyPart.BP_TORSO:
                return bodyTorso;
            case BodyPart.BP_HANDS:
                return bodyHands;
            case BodyPart.BP_LEGS:
                return bodyLegs;
            default:
                return null;
        }
    }

    public abstract void paint(Graphics g);

    public int getPixelX() {
        return drawBlocksX * Tile.WIDTH;
    }

    public int getPixelY() {
        return drawBlocksY * Tile.HEIGHT;
    }

    public int getBlocksX() {
        return drawBlocksX;
    }

    public int getBlocksY() {
        return drawBlocksY;
    }

    public boolean canMove(MoveDirectionType direction, TiledLayer layer) {
        int x = absoluteBlocksX, y = absoluteBlocksY;
        switch (direction) {
            case UP:
                y--;
                break;
            case DOWN:
                y++;
                break;
            case LEFT:
                x--;
                break;
            case RIGHT:
                x++;
                break;
        }

        return layer.getTileObject(x, y).canWalk() & !isThereEnemy(x, y);
    }

    public boolean isThereEnemy(int x, int y) {
        Core core = getInstance();

        BasicEnemy enemy = getEnemyAt(x, y, core);
        if (enemy != null) {
            return (enemy.getAbsoluteBlocksX() == x && enemy.getAbsoluteBlocksY() == y);
        } else {
            return false;
        }
    }

    public void moveUp(TiledLayer layer) {
        drawBlocksY--;
    }

    public void moveDown(TiledLayer layer) {
        drawBlocksY++;
    }

    public void moveLeft(TiledLayer layer) {
        drawBlocksX--;
    }

    public void moveRight(TiledLayer layer) {
        drawBlocksX++;
    }

    public void setDrawBlocksY(int drawBlocksY) {
        this.drawBlocksY = drawBlocksY;
    }

    public void setDrawBlocksX(int drawBlocksX) {
        this.drawBlocksX = drawBlocksX;
    }

    public void setBlocksY(int blocksY) {
        this.drawBlocksY = blocksY;
    }

    public void setBlocksX(int blocksX) {
        this.drawBlocksX = blocksX;
    }

    /**
     * Updates absolute block-coordinates of this BasicStranger.
     */
    public void update() {
        TiledLayer layer = getInstance().getLayer();

        absoluteBlocksX = drawBlocksX - layer.getBlocksX();
        absoluteBlocksY = drawBlocksY - layer.getBlocksY();
    }

    public int getAbsoluteBlocksY() {
        return absoluteBlocksY;
    }

    public int getAbsoluteBlocksX() {
        return absoluteBlocksX;
    }

    public void setCarryVolume(int i) {
        volume = i;
    }

    public void setMaxCarryVolume(int i) {
        maxCarryVolume = i;
    }
}
